/*
 * Copyright (C) 2012-2013 Michael L.R. Marques
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * 
 * Contact: michaellrmarques@gmail.com
 */
package com.jm.jmsql.objects;

import com.jm.jmsql.objects.base.JMSqlObject;
import java.math.BigDecimal;
import java.sql.Array;
import java.sql.Ref;
import java.sql.Struct;
import java.sql.Types;
import java.util.Date;
import javax.swing.Icon;

/**
 *
 * @author Michael L.R. Marques
 */
public class Column extends JMSqlObject {
    
    //
    public static final Integer[] NO_LENGTH_TYPES = new Integer[] { java.sql.Types.BOOLEAN,
                                                                        java.sql.Types.DATE,
                                                                            java.sql.Types.TIME,
                                                                                java.sql.Types.TIMESTAMP };
    //
    public static final Integer[] DECIMAL_TYPES = new Integer[] { java.sql.Types.DECIMAL,
                                                                        java.sql.Types.BIGINT,
                                                                            java.sql.Types.DOUBLE,
                                                                                java.sql.Types.FLOAT,
                                                                                    java.sql.Types.REAL };
    //Java class type
    private Class type;
    // The name of the SQL type
    private String typeName;
    // The length of the column
    private int length;
    // The decimal positions of the column (if numerical)
    private int decimals;
    // The remark/comments/description of the column
    private String description;
    // The ordinal position of the column in the table
    private int index;
    // Can the column be null
    private boolean nullable;
    // Is the column automatically incremented (if numeric)
    private boolean incrimented;
    // Is the column automatically generated
    private boolean generated;
    // Is the column a primary key
    private boolean primarykey;
    
    /**
     * 
     * @param parent
     * @param name
     * @param type
     * @param typeName
     * @param length
     * @param decimals
     * @param description
     * @param index 
     */
    public Column(JMSqlObject parent, String name, int type, String typeName, int length, int decimals, String description, int index) {
        this(parent, name, type, typeName, length, decimals, description, index, false);
    }
    
    /**
     * 
     * @param parent
     * @param name
     * @param type
     * @param typeName
     * @param length
     * @param decimals
     * @param description
     * @param index
     * @param nullable 
     */
    public Column(JMSqlObject parent, String name, int type, String typeName, int length, int decimals, String description, int index, boolean nullable) {
        this(parent, name, type, typeName, length, decimals, description, index, nullable, false);
    }
    
    /**
     * 
     * @param parent
     * @param name
     * @param type
     * @param typeName
     * @param length
     * @param decimals
     * @param description
     * @param index
     * @param nullable
     * @param incremented
     */
    public Column(JMSqlObject parent, String name, int type, String typeName, int length, int decimals, String description, int index, boolean nullable, boolean incremented) {
        this(parent, name, type, typeName, length, decimals, description, index, nullable, incremented, false);
    }
    
    /**
     * 
     * @param parent
     * @param name
     * @param type
     * @param typeName
     * @param length
     * @param decimals
     * @param description
     * @param index
     * @param nullable
     * @param incremented
     * @param generated 
     */
    public Column(JMSqlObject parent, String name, int type, String typeName, int length, int decimals, String description, int index, boolean nullable, boolean incremented, boolean generated) {
        this(parent, name, JdbcJavaType.get(type).getType(), typeName, length, decimals, description, index, nullable, incremented, generated);
    }
    
    /**
     * 
     * @param parent
     * @param name
     * @param type
     * @param typeName
     * @param length
     * @param decimals
     * @param description
     * @param index
     * @param nullable
     * @param incremented
     * @param generated 
     */
    public Column(JMSqlObject parent, String name, Class type, String typeName, int length, int decimals, String description, int index, boolean nullable, boolean incremented, boolean generated) {
        this(parent, name, type, typeName, length, decimals, description, index, false, nullable, incremented, generated);
    }
    
    /**
     * 
     * @param parent
     * @param name
     * @param type
     * @param typeName
     * @param length
     * @param decimals
     * @param index
     * @param primaryKey
     * @param nullable
     * @param incremented
     * @param generated 
     */
    public Column(JMSqlObject parent, String name, Class type, String typeName, int length, int decimals, int index, boolean primaryKey, boolean nullable, boolean incremented, boolean generated) {
        this(parent, name, type, typeName, length, decimals, "", index, primaryKey, nullable, incremented, generated);
    }
    
    /**
     * 
     * @param parent
     * @param name
     * @param type
     * @param typeName
     * @param length
     * @param decimals
     * @param description
     * @param primaryKey
     * @param index
     * @param nullable
     * @param incremented
     * @param generated 
     */
    public Column(JMSqlObject parent, String name, Class type, String typeName, int length, int decimals, String description, int index, boolean primaryKey, boolean nullable, boolean incremented, boolean generated) {
        super(parent, name);
        this.type = type;
        this.typeName = typeName;
        this.length = length;
        this.decimals = decimals;
        this.description = description;
        this.primarykey = primaryKey;
        this.index = index;
        this.nullable = nullable;
        this.incrimented = incremented;
        this.generated = generated;
    }
    
    /**
     * 
     * @return 
     */
    @Override
    public Icon getIcon() {
        return super.getIcon();
    }
    
    /**
     * 
     * @return 
     */
    public Class getType() {
        return this.type;
    }
    
    /**
     * 
     * @return 
     */
    public String getTypeName() {
        return this.typeName;
    }
    
    /**
     * 
     * @return 
     */
    public int getLength() {
        return this.length;
    }
    
    /**
     * 
     * @return 
     */
    public int getDecimals() {
        return this.decimals;
    }
    
    /**
     * 
     * @return 
     */
    public String getDescription() {
       return this.description;
    }
    
    /**
     * 
     * @return 
     */
    public int getIndex() {
        return this.index;
    }
    
    /**
     * 
     * @return 
     */
    public boolean isNullable() {
        return this.nullable;
    }
    
    /**
     * 
     * @return 
     */
    public boolean isAutoIncremented() {
        return this.incrimented;
    }
    
    /**
     * 
     * @return 
     */
    public boolean isAutoGenerated() {
        return this.generated;
    }
    
    /**
     * 
     * @param primaryKey 
     */
    public void setPrimaryKey(boolean primaryKey) {
        this.primarykey = primaryKey;
    }
    
    /**
     * 
     * @return 
     */
    public boolean isPrimaryKey() {
        return this.primarykey;
    }
    
    /**
     * 
     * @return 
     */
    public boolean hasNoLength() {
       //return Arrays.asList(Column.NO_LENGTH_TYPES).contains(this.);
       return false;
    }

    /**
     * 
     * @return 
     */
    public boolean hasDecimals() {
       //return Arrays.asList(Column.DECIMAL_TYPES).contains(this.type);
       return false;
    }
    
    /**
     * 
     * @return 
     */
    @Override public JMSqlObject.Type getObjectType() {
        return JMSqlObject.Type.COLUMN;
    }
    
    /**
     * 
     * @return 
     */
    @Override public int getColumnCount() {
        return 10;
    }
    
    /**
     * 
     * @param index
     * @return 
     */
    @Override public String getColumnName(int index) {
        switch (index) {
            case 0: return "Index";
            case 1: return "Name";
            case 2: return "Type";
            case 3: return "Length";
            case 4: return "Decimals";
            case 5: return "Description";
            case 6: return "Nullable";
            case 7: return "Auto-Incremeneted";
            case 8: return "Auto-Generated";
            case 9: return "Primary Key";
            default: return null;
        }
    }
    
    /**
     * 
     * @param index
     * @return 
     */
    @Override public Object getColumn(int index) {
        switch (index) {
            case 0: return this.index;
            case 1: return getName();
            case 2: return this.typeName;
            case 3: return this.length;
            case 4: return this.decimals;
            case 5: return this.description == null ? "" : this.description;
            case 6: return this.nullable;
            case 7: return this.incrimented;
            case 8: return this.generated;
            case 9: return this.primarykey;
            default: return null;
        }
    }
    
    /**
     * 
     * @param index
     * @return 
     */
    @Override
    public boolean isColumnEditable(int index) {
        switch (index) {
            case 1:;
            case 3:;
            case 4:;
            case 5:;
            case 6:;
            case 7:;
            case 8:;
            case 9: return true;
            default: return false;
        }
    }
    
    /**
     * 
     * @param index
     * @param object 
     */
    @Override
    public void setColumn(int index, Object object) {
        if (isInEditMode()) {
            switch (index) {
                case 1: setName(object.toString()); break;
                case 3: this.length = (int) object; break;
                case 4: this.decimals = (int) object; break;
                case 5: this.description = object.toString(); break;
                case 6: this.nullable = (boolean) object; break;
                case 7: this.incrimented = (boolean) object; break;
                case 8: this.generated = (boolean) object; break;
                case 9: this.primarykey = (boolean) object;
            }
        }
    }
    
    /**
     * 
     */
    public enum JdbcJavaType {
        
        //
        Char(Types.CHAR, String.class),
        //
        VarChar(Types.VARCHAR, String.class),
        //
        LongNVarChar(Types.LONGNVARCHAR, String.class),
        //
        Numeric(Types.NUMERIC, BigDecimal.class),
        //
        Decimal(Types.DECIMAL, BigDecimal.class),
        //
        Bit(Types.BOOLEAN, Boolean.class),
        //
        Integer(Types.INTEGER, Integer.class),
        //
        BigInteger(Types.BIGINT, Long.class),
        //
        SmallInteger(Types.SMALLINT, Short.class),
        //
        Real(Types.REAL, Float.class),
        //
        Float(Types.FLOAT, Float.class),
        //
        Double(Types.DOUBLE, Double.class),
        //
        Clob(Types.CLOB, Byte[].class),
        //
        Blob(Types.BLOB, Byte[].class),
        //
        Binary(Types.BINARY, Byte[].class),
        //
        VarBinary(Types.VARBINARY, Byte[].class),
        //
        Date(Types.DATE, Date.class),
        //
        Time(Types.TIME, Date.class),
        //
        TimeStamp(Types.TIMESTAMP, Date.class),
        //
        Array(Types.ARRAY, Array.class),
        //
        Struct(Types.STRUCT, Struct.class),
        //
        Ref(Types.REF, Ref.class),
        //
        Class(Types.JAVA_OBJECT, Class.class),
        //
        Object(Types.OTHER, Object.class);
        
        //
        private int jdbc;
        //
        private Class type;
        
        /**
         * 
         * @param jdbc
         * @param type 
         */
        private JdbcJavaType(int jdbc, Class type) {
            this.jdbc = jdbc;
            this.type = type;
        }
        
        /**
         * 
         * @return 
         */
        public int getJdbcType() {
            return this.jdbc;
        }
        
        /**
         * 
         * @return 
         */
        public Class getType() {
            return this.type;
        }
        
        /**
         * 
         * @param jdbc
         * @return 
         */
        public static JdbcJavaType get(int jdbc) {
            for (JdbcJavaType type : JdbcJavaType.values()) {
                if (type.jdbc == jdbc) {
                    return type;
                }
            }
            return Object;
        }
        
        /**
         * 
         * @param type
         * @return 
         */
        public static JdbcJavaType get(Class type) {
            for (JdbcJavaType jdbc : JdbcJavaType.values()) {
                if (jdbc.type == type) {
                    return jdbc;
                }
            }
            return Object;
        }
        
    };
    
    /**
     * 
     * @param type
     * @return 
     *
    public static Class jdbcToJavaTypes(int type) {
        switch (type) {
            case Types.CHAR:;
            case Types.VARCHAR:;
            case Types.LONGNVARCHAR: return String.class;
            case Types.NUMERIC:;
            case Types.DECIMAL: return BigDecimal.class;
            case Types.BIT: return Boolean.class;
            case Types.INTEGER: return Integer.class;
            case Types.BIGINT: return Long.class;
            case Types.REAL:;
            case Types.FLOAT: return Float.class;
            case Types.DOUBLE: return Double.class;
            case Types.CLOB:;
            case Types.BLOB:;
            case Types.BINARY:;
            case Types.VARBINARY:;
            case Types.LONGVARBINARY: return byte[].class;
            case Types.DATE:;
            case Types.TIME:;
            case Types.TIMESTAMP: return Date.class;
            case Types.ARRAY: return Array.class;
            case Types.STRUCT: return Struct.class;
            case Types.REF: return Ref.class;
            case Types.JAVA_OBJECT: return Class.class;
            default: return Object.class;
        }
    
    }
    */
    
}
